package com.coderfans.serializetest;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.ByteArraySerializer;
import com.caucho.hessian.io.*;

import java.io.*;

/**
 * 序列化工具类
 * http://www.ijiuwen.com/blog/1004286372888576
 * Created by 58 on 2016-8-9.
 */
public class SerializeUtil {

    private static SerializerFactory serializerFactory;

    /**
     * 普通的序列化方法，Java内置实现
     * @param value
     * @param <T>
     * @return
     * @throws SerializeException 自定义序列化异常
     */
    public static <T> byte[] normalSerialize(T value)throws SerializeException{
        if(value == null){
            throw  new NullPointerException("can't serialize null");
        }
        byte[] result = null;
        ByteArrayOutputStream outputStream = null;
        ObjectOutputStream objectOutputStream = null;

        try {
            outputStream = new ByteArrayOutputStream();
            objectOutputStream = new ObjectOutputStream(outputStream);
            objectOutputStream.writeObject(value);
            result = outputStream.toByteArray();
        } catch (IOException e) {
            throw  new SerializeException("the object is not implements Serializable");
        }finally {
            close(objectOutputStream);
            close(outputStream);
        }
        return result;
    }

    /**
     * 普通的反序列化方法，Java内置实现
     * @param clazz
     * @param objectByte
     * @param <T>
     * @return
     * @throws SerializeException  自定义序列化异常
     */
    public static <T> T normalDesrialize(Class<T> clazz,byte [] objectByte) throws SerializeException{
        T object = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream  ois = null;
        try {
            if(objectByte != null){
                bis = new ByteArrayInputStream(objectByte);
                ois = new ObjectInputStream(bis);

                object = (T) ois.readObject();

            }
        } catch (IOException e) {
            throw new SerializeException(
                    String.format("Caught IOException decoding %d bytes of data", objectByte.length) + e);
        } catch (ClassNotFoundException e) {
            throw  new SerializeException(
                    String.format("Caught CNFE decoding %d bytes of data", objectByte.length) + e);
        }finally {
            close(ois);
            close(bis);
        }
        return object;
    }

    /**
     * Java关闭序列化，反序列化流 公用方法
     * @param closeable
     * @throws SerializeException  自定义序列化异常
     */
    public static void close(Closeable closeable)throws SerializeException {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (Exception e) {
                throw new SerializeException(e.getMessage());
            }
        }
    }

    /**
     * fastjson方式序列化对象类为json字符串
     * @param clazz  需要序列化的对象
     * @return  返回序列化后的字符串
     * @throws SerializeException
     */
    public static <T> byte[] fastjsonSerialize(T clazz)throws SerializeException{
        if(clazz == null){
            throw new SerializeException("clazz is null,can't be fastjsonSerialized.");
        }
        return JSON.toJSONString(clazz).getBytes();
    }

    /**
     * fastjson方式反序列化json字符串为Java对象
     * @param objectStr  json字符串
     * @param clazz      Java对象的类
     * @param <T>        泛型
     * @return
     */
    public static <T> T fastjsonDesrialize(String objectStr,Class<T> clazz) throws SerializeException{
        if(objectStr.equals("") || objectStr == null){
            throw new SerializeException("objectStr is null,can't be jsonDesrialized ");
        }
        return JSON.parseObject(objectStr,clazz);
    }


    public static SerializerFactory getSerializerFactory(){
        serializerFactory = new SerializerFactory();
        return serializerFactory;
    }

    /**
     * hessian方式序列化对象类为字节数组
     * @param object
     * @param <T>
     * @return
     * @throws SerializeException
     */
    public static <T> byte[]  hessianSerialize(T object)throws SerializeException{
        if(object == null){
            throw new SerializeException("object is null,can't be hessian serialized.");
        }
        byte [] result = null;
        ByteArrayOutputStream bos = null;
        HessianOutput hessianSerializerOutput = null;
        try {
            bos = new ByteArrayOutputStream();
            hessianSerializerOutput = new HessianOutput(bos);
            hessianSerializerOutput.setSerializerFactory(getSerializerFactory());
            //write本身是线程安全的
            hessianSerializerOutput.writeObject(object);
            bos.close();
            result = bos.toByteArray();
            hessianSerializerOutput.close();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(bos != null){
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    /**
     * hessian方式反序列化字符数组为对象
     * @param resultClass
     * @param bytes
     * @param <T>
     * @return
     * @throws SerializeException
     */
    public static <T> T hessianDeserialize(Class<T> resultClass,byte [] bytes) throws SerializeException {
        if(bytes == null){
            throw  new NullPointerException();
        }
        T result = null;
        ByteArrayInputStream bis = null;
        HessianInput hessianInput = null;
        try {
            bis = new ByteArrayInputStream(bytes);

            hessianInput = new HessianInput(bis);
            hessianInput.setSerializerFactory(getSerializerFactory());
            result = (T)hessianInput.readObject(resultClass.getClass());
            bis.close();
            hessianInput.close();
        } catch (Exception e) {
            e.printStackTrace();
            throw new SerializeException(e.getMessage());
        }finally {
            if(bis != null){
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            hessianInput.close();
        }
        return result;
    }

    /**
     * 字符串的方式实现序列化
     * @param object
     * @param <T>
     * @return
     */
    public static <T> byte[] stringSerialize(T object){
        return object.toString().getBytes();
    }


    /**
     * 字符串方式 反序列化
     * @param bytes
     * @return
     */
    public static String stringDeserialize(byte [] bytes){
        return new String(bytes);
    }

}
